// Copyright (C) ZHENG Zhong <heavyzheng nospam-at gmail D0T com>
//
// $Id: attribute_map.hpp 317 2009-01-12 11:10:14Z heavyzheng $
//

#ifndef ZZHENG_XML_DOM_LIBXML2_ATTRIBUTE_MAP_HPP_20080726__
#define ZZHENG_XML_DOM_LIBXML2_ATTRIBUTE_MAP_HPP_20080726__

#include <zzheng/xml/config.hpp>
#include <zzheng/xml/dom/types.hpp>
#include <zzheng/xml/dom/basic_node_ptr.hpp>
#include <zzheng/xml/dom/basic_node_iterator.hpp>
#include <zzheng/xml/dom/node_proxy.hpp>

#include <zzheng/xml/dom/libxml2/attribute.hpp>
#include <zzheng/xml/dom/libxml2/libxml2_fwd.hpp>

#include <utility>
#include <string>

namespace zzheng {
namespace xml {
namespace dom {
namespace libxml2_ {

    class element;

    //! This class represents an attribute map attached to an element. It may be viewed as a
    //! container of pointers to attribute. This class provides a similar API as std::map, the key
    //! of each attribute is its local name and namespace URI.
    class attribute_map {

        friend class element;

    public:

        ////////////////////////////////////////////////////////////////////////////////////////////
        // typedefs
        //

        typedef basic_node_ptr<attribute>            auto_type;

        typedef attribute&                           reference;
        typedef const attribute&                     const_reference;

        typedef basic_node_iterator<attribute>       iterator;
        typedef basic_node_iterator<const attribute> const_iterator;

    public:

        ////////////////////////////////////////////////////////////////////////////////////////////
        // capacity
        //

        //! Checks if this container is empty.
        //! \return true if this container is empty, false otherwise.
        bool empty() const;

        //! Returns the number of items in this map.
        //! \return the number of items in this map.
        size_type size() const;

        ////////////////////////////////////////////////////////////////////////////////////////////
        // iterators
        //

        iterator begin();

        iterator end();

        const_iterator begin() const;

        const_iterator end() const;

        ////////////////////////////////////////////////////////////////////////////////////////////
        // find
        //

        iterator find(const std::string& name);

        const_iterator find(const std::string& name) const;

        iterator find(const std::string& name, const std::string& uri);

        const_iterator find(const std::string& name, const std::string& uri) const;

        ////////////////////////////////////////////////////////////////////////////////////////////
        // modifiers
        //

        //! Removes all the attribute objects in this map.
        //! \todo TODO: implement me!
        void clear();

        //! Inserts an attribute to the map. Like std::map::insert, this function will insert the
        //! attribute to the map only if no attribute with the same local name and namespace URI
        //! already exists.
        //! \param attr  the attribute to insert.
        //! \return a std::pair containing a pointer to the attribute inserted (or an existing
        //!         attribute with the same name and namespace URI), and a boolean which is true
        //!         if an insertion took place.
        std::pair<basic_node_ptr<attribute>, bool> insert(const attribute_proxy& attr);

        //! \todo TODO: implement me!
        std::pair<iterator, bool> insert(const basic_node_ptr<attribute>& attr);

        //! Inserts an attribute to the map. If an attribute with the same local name and namespace
        //! URI already exists, this function will update its value.
        //! \param attr  the attribute to insert (or update if necessary).
        //! \return a pointer to the attribute inserted or updated.
        basic_node_ptr<attribute> insert_update(const attribute_proxy& attr);

        //! \todo TODO: implement me!
        void erase(iterator pos);

        //! \todo TODO: implement me!
        void erase(iterator first, iterator last);

        //! \todo TODO: implement me!
        size_type erase(const std::string& name);

        //! \todo TODO: implement me!
        size_type erase(const std::string& name, const std::string& uri);

    private:

        ////////////////////////////////////////////////////////////////////////////////////////////
        // private
        //

        explicit attribute_map(xmlNode* px);

        //! Non-implemented copy constructor.
        attribute_map(const attribute_map&);

        //! Non-implemented copy assignment.
        attribute_map& operator=(const attribute_map&);

        ~attribute_map();

        xmlNode* raw() {
            assert(raw_ != 0 && "Underlying libxml2 node should not be null.");
            return raw_;
        }

        const xmlNode* raw() const {
            assert(raw_ != 0 && "Underlying libxml2 node should not be null.");
            return raw_;
        }

        element& owner();

        const element& owner() const;

        const attribute* first_() const;

        const attribute* find_(const std::string& name, const std::string& uri) const;

        attribute* create_attr_(const attribute_proxy& attr);

    private:

        xmlNode* raw_; //!< The libxml2 element holding the attribute map.

    }; // class attribute_map

} // namespace zzheng::xml::dom::libxml2_
} // namespace zzheng::xml::dom
} // namespace zzheng::xml
} // namespace zzheng

#endif // ZZHENG_XML_DOM_LIBXML2_ATTRIBUTE_MAP_HPP_20080726__


